const { KeyEventOriginal, IKeyListener } = require('./IKeyListener');
const CacheHolder = require('./CacheHolder');
const KeyRuleHolder = require('./KeyRuleHolder');
const SlidingWindow = require('./SlidingWindow');

/**
 * 热键监听器实现
 * 实现了热键的监测和推送逻辑
 */
class KeyListener extends IKeyListener {
  constructor() {
    super();
    
    // 热键缓存
    this.hotCache = new Map();
    
    // 推送器列表
    this.pushers = [];
    
    // 日志记录开关（默认开启）
    this.loggerOn = true;
    
    // 分隔符
    this.SPLITER = '-';
  }
  
  /**
   * 设置推送器
   * @param {Array} pushers - 推送器列表
   */
  setPushers(pushers) {
    this.pushers = pushers;
  }
  
  /**
   * 设置日志记录开关
   * @param {boolean} on - 是否开启
   */
  setLoggerOn(on) {
    this.loggerOn = on;
  }
  
  /**
   * 处理新的键
   * @param {Object} hotKeyModel - 热键模型
   * @param {string} original - 来源
   */
  newKey(hotKeyModel, original) {
    // 构建缓存键
    const key = this._buildKey(hotKeyModel);
    
    // 判断是不是刚热不久
    if (this.hotCache.has(key)) {
      return;
    }
    
    // 在Node.js单线程环境中，不存在Java中提到的多线程问题
    // 但在多进程环境下，仍需要注意数据一致性问题
    
    // 获取或创建滑动窗口
    const slidingWindow = this._checkWindow(hotKeyModel, key);
    
    // 判断是否达到热键阈值
    const hot = slidingWindow.addCount(hotKeyModel.count || 1);
    
    if (!hot) {
      // 如果没达到热键阈值，更新缓存
      CacheHolder.getCache(hotKeyModel.appName).set(key, slidingWindow);
    } else {
      // 达到热键阈值
      this.hotCache.set(key, 1);
      
      // 从计数缓存中删除该键
      CacheHolder.getCache(hotKeyModel.appName).del(key);
      
      // 设置热键创建时间
      hotKeyModel.createTime = Date.now();
      
      // 记录日志
      if (this.loggerOn) {
        console.log(`新热键事件: ${hotKeyModel.key}`);
      }
      
      // 推送到各客户端
      for (const pusher of this.pushers) {
        pusher.push(hotKeyModel);
      }
    }
  }
  
  /**
   * 删除键
   * @param {Object} hotKeyModel - 热键模型
   * @param {string} original - 来源
   */
  removeKey(hotKeyModel, original) {
    // 构建缓存键
    const key = this._buildKey(hotKeyModel);
    
    // 从热键缓存移除
    this.hotCache.delete(key);
    
    // 从计数缓存移除
    CacheHolder.getCache(hotKeyModel.appName).del(key);
    
    // 设置删除时间
    hotKeyModel.createTime = Date.now();
    
    // 记录日志
    console.log(`键删除事件: ${hotKeyModel.key}`);
    
    // 推送删除事件到各客户端
    for (const pusher of this.pushers) {
      pusher.remove(hotKeyModel);
    }
  }
  
  /**
   * 检查并获取滑动窗口
   * @param {Object} hotKeyModel - 热键模型
   * @param {string} key - 缓存键
   * @returns {SlidingWindow} 滑动窗口实例
   * @private
   */
  _checkWindow(hotKeyModel, key) {
    // 尝试从缓存获取滑动窗口
    let slidingWindow = CacheHolder.getCache(hotKeyModel.appName).get(key);
    
    // 如果不存在，创建新的滑动窗口
    if (!slidingWindow) {
      // 获取该键的规则
      const keyRule = KeyRuleHolder.getRuleByAppAndKey(hotKeyModel);
      
      // 创建新的滑动窗口
      slidingWindow = new SlidingWindow(keyRule.interval, keyRule.threshold);
      
      // 将滑动窗口放入缓存
      CacheHolder.getCache(hotKeyModel.appName).set(key, slidingWindow);
    }
    
    return slidingWindow;
  }
  
  /**
   * 构建缓存键
   * @param {Object} hotKeyModel - 热键模型
   * @returns {string} 缓存键
   * @private
   */
  _buildKey(hotKeyModel) {
    return [hotKeyModel.appName, hotKeyModel.keyType, hotKeyModel.key].join(this.SPLITER);
  }
}

module.exports = KeyListener;
